<template>
  <div class="p-6 bg-white rounded-lg shadow-lg">
    <h3 class="text-xl font-bold mb-4 text-gray-800">事件循环可视化</h3>
    <div class="space-y-6">
      <!-- 控制面板 -->
      <div class="space-y-3">
        <div class="flex flex-wrap gap-2">
          <button
            @click="addSyncTask"
            class="px-3 py-1 bg-green-500 text-white rounded text-sm hover:bg-green-600 transition-colors"
          >
            添加同步任务
          </button>
          <button
            @click="addMicrotask"
            class="px-3 py-1 bg-yellow-500 text-white rounded text-sm hover:bg-yellow-600 transition-colors"
          >
            添加微任务
          </button>
          <button
            @click="addMacrotask"
            class="px-3 py-1 bg-red-500 text-white rounded text-sm hover:bg-red-600 transition-colors"
          >
            添加宏任务
          </button>
          <button
            @click="addNextTick"
            class="px-3 py-1 bg-purple-500 text-white rounded text-sm hover:bg-purple-600 transition-colors"
          >
            添加 nextTick
          </button>
        </div>

        <div class="flex flex-wrap gap-2 items-center">
          <button
            @click="startExecution"
            :disabled="isRunning"
            class="px-4 py-1 bg-blue-500 text-white rounded text-sm hover:bg-blue-600 transition-colors disabled:opacity-50"
          >
            开始执行
          </button>
          <button
            @click="resetQueue"
            class="px-3 py-1 bg-gray-500 text-white rounded text-sm hover:bg-gray-600 transition-colors"
          >
            重置队列
          </button>

          <!-- 新增配置选项 -->
          <div class="flex items-center gap-4 ml-4">
            <label class="text-sm text-gray-600">
              <input v-model="enableNewTasks" type="checkbox" class="mr-1" />
              产生新任务 ({{ newTasksGenerated }}/{{ maxNewTasks }})
            </label>
            <label class="text-sm text-gray-600">
              <input v-model="slowMode" type="checkbox" class="mr-1" />
              慢速模式
            </label>
          </div>
        </div>
      </div>

      <!-- 可视化区域 -->
      <div class="visualizer-container">
        <!-- 调用栈 -->
        <div class="stack-container">
          <h4 class="font-semibold mb-2 text-center">调用栈 (Call Stack)</h4>
          <div class="stack">
            <TransitionGroup name="stack" tag="div">
              <div
                v-for="task in callStack"
                :key="task.id"
                :class="[
                  getTaskClass(task.type),
                  currentExecutingTask?.id === task.id ? 'executing' : '',
                ]"
                class="task-item"
              >
                {{ task.name }}
                <span v-if="currentExecutingTask?.id === task.id" class="executing-indicator"
                  >⚡</span
                >
              </div>
            </TransitionGroup>
          </div>
        </div>

        <!-- 任务队列 -->
        <div class="queues-container">
          <!-- 微任务队列 -->
          <div class="queue-section">
            <h4 class="font-semibold mb-2 text-center">微任务队列</h4>
            <div class="queue microtask-queue">
              <TransitionGroup name="queue" tag="div" class="queue-items">
                <div
                  v-for="task in microtaskQueue"
                  :key="task.id"
                  :class="[
                    getTaskClass(task.type),
                    currentExecutingTask?.id === task.id ? 'executing' : '',
                  ]"
                  class="task-item"
                >
                  {{ task.name }}
                  <span v-if="currentExecutingTask?.id === task.id" class="executing-indicator"
                    >⚡</span
                  >
                </div>
              </TransitionGroup>
            </div>
          </div>

          <!-- 宏任务队列 -->
          <div class="queue-section">
            <h4 class="font-semibold mb-2 text-center">宏任务队列</h4>
            <div class="queue macrotask-queue">
              <TransitionGroup name="queue" tag="div" class="queue-items">
                <div
                  v-for="task in macrotaskQueue"
                  :key="task.id"
                  :class="[
                    getTaskClass(task.type),
                    currentExecutingTask?.id === task.id ? 'executing' : '',
                  ]"
                  class="task-item"
                >
                  {{ task.name }}
                  <span v-if="currentExecutingTask?.id === task.id" class="executing-indicator"
                    >⚡</span
                  >
                </div>
              </TransitionGroup>
            </div>
          </div>
        </div>
      </div>

      <!-- 执行日志 -->
      <div class="bg-gray-100 p-4 rounded-lg">
        <h4 class="font-semibold mb-2">执行日志：</h4>
        <div class="execution-log">
          <div
            v-for="(log, index) in executionLogs"
            :key="index"
            :class="getLogClass(log.type)"
            class="py-1 px-2 mb-1 rounded"
          >
            <span class="font-mono text-sm">{{ log.message }}</span>
          </div>
        </div>
      </div>

      <!-- 说明 -->
      <div class="bg-blue-50 p-4 rounded-lg">
        <h4 class="font-semibold mb-2">执行规则：</h4>
        <ul class="text-sm space-y-1">
          <li>1. 首先执行调用栈中的同步任务</li>
          <li>2. 调用栈清空后，执行所有微任务队列中的任务</li>
          <li>3. 微任务队列清空后，从宏任务队列取出一个任务执行</li>
          <li>4. 重复步骤 1-3，直到所有队列都空</li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

interface Task {
  id: number
  name: string
  type: 'sync' | 'microtask' | 'macrotask' | 'nexttick'
}

interface LogEntry {
  message: string
  type: 'sync' | 'microtask' | 'macrotask' | 'nexttick'
}

const callStack = ref<Task[]>([])
const microtaskQueue = ref<Task[]>([])
const macrotaskQueue = ref<Task[]>([])
const executionLogs = ref<LogEntry[]>([])
const isRunning = ref(false)
const enableNewTasks = ref(true)
const slowMode = ref(false)
const currentExecutingTask = ref<Task | null>(null)

let taskId = 0
const newTasksGenerated = ref(0)
const maxNewTasks = ref(3) // 最多产生3个新任务

const getTaskClass = (type: string) => {
  const classes = {
    sync: 'bg-green-500 text-white',
    microtask: 'bg-yellow-500 text-white',
    macrotask: 'bg-red-500 text-white',
    nexttick: 'bg-purple-500 text-white',
  }
  return classes[type as keyof typeof classes] || ''
}

const getLogClass = (type: string) => {
  const classes = {
    sync: 'bg-green-100 border-l-4 border-green-500',
    microtask: 'bg-yellow-100 border-l-4 border-yellow-500',
    macrotask: 'bg-red-100 border-l-4 border-red-500',
    nexttick: 'bg-purple-100 border-l-4 border-purple-500',
  }
  return classes[type as keyof typeof classes] || ''
}

const addSyncTask = () => {
  const task: Task = {
    id: ++taskId,
    name: `同步任务 ${taskId}`,
    type: 'sync',
  }
  callStack.value.push(task)
}

const addMicrotask = () => {
  const task: Task = {
    id: ++taskId,
    name: `Promise ${taskId}`,
    type: 'microtask',
  }
  microtaskQueue.value.push(task)
}

const addMacrotask = () => {
  const task: Task = {
    id: ++taskId,
    name: `setTimeout ${taskId}`,
    type: 'macrotask',
  }
  macrotaskQueue.value.push(task)
}

const addNextTick = () => {
  const task: Task = {
    id: ++taskId,
    name: `nextTick ${taskId}`,
    type: 'nexttick',
  }
  // nextTick 本质上是微任务，但优先级可能不同
  microtaskQueue.value.unshift(task) // 添加到微任务队列的前面
}

const resetQueue = () => {
  callStack.value = []
  microtaskQueue.value = []
  macrotaskQueue.value = []
  executionLogs.value = []
  isRunning.value = false
  currentExecutingTask.value = null
  taskId = 0
  newTasksGenerated.value = 0 // 重置新任务计数器
}

const addLog = (message: string, type: LogEntry['type']) => {
  executionLogs.value.push({ message, type })
}

const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

const addNewTaskWithDelay = async (
  taskName: string,
  taskType: 'microtask' | 'macrotask',
  delay = 300,
) => {
  // 检查是否还能产生新任务
  if (newTasksGenerated.value >= maxNewTasks.value) {
    addLog(`⚠️ 已达到新任务生成上限 (${maxNewTasks.value}个)`, 'sync')
    return
  }

  await sleep(delay)
  newTasksGenerated.value++

  const newTask: Task = {
    id: ++taskId,
    name: taskName,
    type: taskType,
  }

  if (taskType === 'microtask') {
    microtaskQueue.value.push(newTask)
  } else {
    macrotaskQueue.value.push(newTask)
  }

  addLog(`💫 ${taskName} 被动态添加 (${newTasksGenerated.value}/${maxNewTasks.value})`, taskType)
}

const startExecution = async () => {
  if (isRunning.value) return

  isRunning.value = true
  newTasksGenerated.value = 0 // 重置新任务计数器
  addLog('🚀 开始执行事件循环', 'sync')

  const speed = slowMode.value ? 1200 : 600

  try {
    let loopCount = 0

    while (
      callStack.value.length > 0 ||
      microtaskQueue.value.length > 0 ||
      macrotaskQueue.value.length > 0
    ) {
      loopCount++
      addLog(`--- 第 ${loopCount} 轮事件循环 ---`, 'sync')

      // 1. 执行调用栈中的所有同步任务
      while (callStack.value.length > 0) {
        const task = callStack.value[0]
        currentExecutingTask.value = task
        addLog(`⚡ 正在执行同步任务: ${task.name}`, task.type)
        await sleep(speed)

        callStack.value.shift()
        currentExecutingTask.value = null
        await sleep(speed * 0.3)
      }

      // 2. 执行所有微任务
      let microtaskCount = 0
      while (microtaskQueue.value.length > 0) {
        const task = microtaskQueue.value[0] // 获取第一个任务但不移除
        microtaskCount++

        // 设置当前执行任务（显示小闪电）
        currentExecutingTask.value = task
        addLog(`🔄 执行微任务 ${microtaskCount}: ${task.name}`, task.type)
        await sleep(speed * 0.8)

        // 执行完毕后再从队列移除
        microtaskQueue.value.shift()
        currentExecutingTask.value = null

        // 根据设置决定是否产生新的微任务
        if (enableNewTasks.value && newTasksGenerated.value < maxNewTasks.value) {
          // 第一个 Promise 任务产生新的微任务链
          if (
            task.name.includes('Promise') &&
            !task.name.includes('链') &&
            microtaskQueue.value.length < 2
          ) {
            addNewTaskWithDelay(`Promise链-${taskId + 1}`, 'microtask', speed * 0.5)
          }

          // 第一个 nextTick 可能触发新的宏任务
          if (
            task.name.includes('nextTick') &&
            !task.name.includes('触发') &&
            macrotaskQueue.value.length < 2
          ) {
            addNewTaskWithDelay(`nextTick触发的setTimeout-${taskId + 1}`, 'macrotask', speed * 0.6)
          }
        }
      }

      if (microtaskCount > 0) {
        addLog(`✅ 微任务队列已清空 (执行了${microtaskCount}个微任务)`, 'microtask')
      }

      // 3. 执行一个宏任务
      if (macrotaskQueue.value.length > 0) {
        const task = macrotaskQueue.value[0] // 获取第一个任务但不移除

        // 设置当前执行任务（显示小闪电）
        currentExecutingTask.value = task
        addLog(`⏰ 执行宏任务: ${task.name}`, task.type)
        await sleep(speed)

        // 执行完毕后再从队列移除
        macrotaskQueue.value.shift()
        currentExecutingTask.value = null

        // 宏任务执行可能产生微任务
        if (enableNewTasks.value && task.name.includes('setTimeout')) {
          addNewTaskWithDelay(`${task.name}产生的Promise-${taskId + 1}`, 'microtask', speed * 0.4)
        }
      }

      // 每轮循环后稍作停顿，让用户看清过程
      await sleep(speed * 0.5)
    }

    addLog('🎉 所有任务执行完毕！', 'sync')
  } catch (error) {
    addLog(`❌ 执行出错: ${error}`, 'sync')
  } finally {
    isRunning.value = false
  }
}
</script>

<style scoped lang="scss">
.visualizer-container {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 24px;
  min-height: 400px;

  @media (max-width: 768px) {
    grid-template-columns: 1fr;
    gap: 16px;
  }
}

.stack-container {
  display: flex;
  flex-direction: column;
}

.stack {
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  min-height: 300px;
  padding: 16px;
  background: linear-gradient(135deg, #f9fafb, #f3f4f6);
  position: relative;

  &::before {
    content: '栈底';
    position: absolute;
    bottom: 8px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 12px;
    color: #6b7280;
  }
}

.queues-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.queue-section {
  flex: 1;
}

.queue {
  border: 2px solid #e5e7eb;
  border-radius: 8px;
  min-height: 120px;
  padding: 16px;
  background: linear-gradient(135deg, #fef3c7, #fde68a);

  &.macrotask-queue {
    background: linear-gradient(135deg, #fee2e2, #fecaca);
  }
}

.queue-items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.task-item {
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  cursor: default;
  transition: all 0.3s ease;
  position: relative;

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
  }

  &.executing {
    animation: pulse 1s infinite;
    transform: scale(1.05);
    box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
    border: 2px solid #3b82f6;
  }
}

.executing-indicator {
  position: absolute;
  top: -5px;
  right: -5px;
  background: #fbbf24;
  border-radius: 50%;
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 8px;
  animation: bounce 0.5s infinite alternate;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
  }
  50% {
    box-shadow: 0 0 25px rgba(59, 130, 246, 0.8);
  }
  100% {
    box-shadow: 0 0 15px rgba(59, 130, 246, 0.5);
  }
}

@keyframes bounce {
  0% {
    transform: translateY(0px);
  }
  100% {
    transform: translateY(-3px);
  }
}

// Vue 过渡动画
.stack-enter-active,
.stack-leave-active {
  transition: all 0.5s ease;
}

.stack-enter-from {
  opacity: 0;
  transform: translateX(-50px);
}

.stack-leave-to {
  opacity: 0;
  transform: translateX(50px);
}

.queue-enter-active,
.queue-leave-active {
  transition: all 0.4s ease;
}

.queue-enter-from {
  opacity: 0;
  transform: scale(0.8);
}

.queue-leave-to {
  opacity: 0;
  transform: scale(0.8);
}

.execution-log {
  max-height: 250px;
  overflow-y: auto;

  &::-webkit-scrollbar {
    width: 6px;
  }

  &::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }

  &::-webkit-scrollbar-thumb {
    background: #c1c1c1;
    border-radius: 3px;

    &:hover {
      background: #a8a8a8;
    }
  }
}
</style>
